<?php

class GenericClass Extends Entity {	protected function __meta() {}}

class GenericDao
{
	protected static $dao = null;
	protected $entityName = "";
	protected $entity = null;
	
	protected $totalRows = 0;
	
	public function __construct($entity)
	{
		$this->setEntity($entity);
	}
	
	/**
	 * getter entity
	 *
	 * @return String
	 */
	public function getEntity()
	{
		return $this->entity;
	}
	
	/**
	 * Setter entity
	 *
	 * @param String entity
	 */
	public function setEntity($entity)
	{
		if($this->entity instanceof Entity)
		{
			$this->entity = $entity;
			$this->entityName = get_class($entity);
		} else {
			$this->entity = new $entity();
			$this->entityName = $entity;
		}
	}

	/**
	 * Get The shared Dao
	 *
	 * @return Dao
	 */
	private function getDao()
	{
		if(self::$dao == null)
		{
			self::$dao = new Dao();
		}
		return self::$dao;
	}

	protected function setTotalRows()
	{
		$this->totalRows = $this->getDao()->getTotalRows();
	}
	
	public function save(Entity $entity)
	{
		if($entity->getId() == null)
		{
			$sql = new Insert($entity);
			$this->getDao()->execute($sql);
			return $entity;
		} else {
			$sql = new Update($entity);
			$this->getDao()->execute($sql);
			return $entity;			
		}
	}
	
	public function findAll($page = null,$pagesize = 30)
	{
		$sql = new Select($this->entity,$page,$pagesize);
		$this->getDao()->execute($sql);
		$this->setTotalRows();
		return $sql->getResultSet();
	}
	
	protected function isInteger($input)
	{
    	return(ctype_digit(strval($input)));
	}
	
	public function findById($id)
	{
		
		if(!$this->isInteger($id))
			throw new Exception("Trying to find id of non-int");
		
		$sql = new Select($this->entity);
		$sql->setWhere($this->entity->getMetaAlias().".id = $id");
		$this->getDao()->execute($sql);
		
		$results = $sql->getResultSet();
		$size = sizeof($results);
		
		if($size == 0)
			return null;
		else if($size == 1)
			return $results[0];
		else
			throw new Exception("FindById: Found multiple($size) enties for ".get_class($this->entity)."@$id");
	}
	
	public function findByCriteria($where,$params=array(),$page = null,$pagesize = 30)
	{
		$sql = new Select($this->entity,$page,$pagesize);
		$sql->addParam($params);
		$sql->setWhere($where);
		$this->getDao()->execute($sql);
		$this->setTotalRows();
		return $sql->getResultSet();		
	}
	
	public function search($target,$page = null,$pagesize = 30)
	{
		$sql = new Select($this->entity,$page,$pagesize);
		$sql->search($target);
		$this->getDao()->execute($sql);
		$this->setTotalRows();
		return $sql->getResultSet();
	}
	
	public function activate(Entity $entity)
	{
		$entity->setActive(1);
		$this->save($entity);
	}
	
	public function deactivate(Entity $entity)
	{
		$entity->setActive(0);
		$this->save($entity);		
	}
	
	public function executeStatement(BaseStatement $sql)
	{
		$this->getDao()->execute($sql);
		$this->setTotalRows();
		return $sql->getResultSet();		
	}

	protected function insertManyToMany(Entity $left,Entity $right,ManyToMany $field)
	{
		$joinTableClassName = $field->generateJoinTableName();
		eval('class '.$joinTableClassName.' extends GenericClass {}');

		$class = new $joinTableClassName();
		$class->{$field->field.'Id'} = $left->getId();
		$class->{$field->otherSideField.'Id'} = $right->getId();
		
		$this->save($class);
	}
	
	protected function searchForField($fieldClass,$joinClass)
	{
		foreach(Map::getFields($fieldClass) as $descriptor)
		{
			if($descriptor instanceof ManyToMany && $descriptor->class == $joinClass)
			{
				return $descriptor;
			}
		}
		
		return null;
	}
	
	protected function deactivateManyToMany(Entity $left, Entity $right, ManyToMany $field)
	{
		$joinTableClassName = $field->generateJoinTableName();
		eval('class '.$joinTableClassName.' extends GenericClass {}');

		$select = new Select(new $joinTableClassName(),0,1);
		$select->setWhere($field->field.'Id = ? and '.$field->otherSideField.'Id = ?');
		$select->addParam(array($left->getId(),$right->getId()));
		
		$dao = $this->getDao();
		$dao->execute($select);
		$results = $select->getResultSet();
		
		if($results == null || count($results) == 0)
			throw new Exception("Invalid ManyToMany Relationship.");

		$this->deactivate($results[0]);
	}
	
	public function addManyToMany(Entity $left, Entity $right,$field = "")
	{
		$leftClass = get_class($left);
		$rightClass = get_class($right);
		
		if($field == "")
		{
			// Left Search
			if($descriptor = $this->searchForField($leftClass,$rightClass) != null)
			{
				$this->insertManyToMany($left,$right,$descriptor);
			} else if($descriptor = $this->searchForField($rightClass,$leftClass) != null)
			{
				$this->insertManyToMany($right,$left,$descriptor);
				return;
			} else {
				throw new Exception('Cannot find compatible join on '.$leftClass.' or '.$rightClass.'.');
			}
		} else {
			if(Map::hasField($leftClass,$field))
			{
				$this->insertManyToMany($left,$right,Map::getField($leftClass,$field));
			} else if(Map::hasField($rightClass,$field))
			{
				$this->insertManyToMany($right,$left,Map::getField($rightClass,$field));
			} else {
				throw new Exception("Field: ".$field.' doesnt exist on '.$leftClass.' or '.$rightClass.'.');
			}
		}
	}
	
	public function removeManyToMany(Entity $left, Entity $right,$field = "")
	{
		$leftClass = get_class($left);
		$rightClass = get_class($right);
		
		if($field == "")
		{
			// Left Search
			if($descriptor = $this->searchForField($leftClass,$rightClass) != null)
			{
				$this->deactivateManyToMany($left,$right,$descriptor);
			} else if($descriptor = $this->searchForField($rightClass,$leftClass) != null)
			{
				$this->deactivateManyToMany($right,$left,$descriptor);
				return;
			} else {
				throw new Exception('Cannot find compatible join on '.$leftClass.' or '.$rightClass.'.');
			}
		} else {
			if(Map::hasField($leftClass,$field))
			{
				$this->deactivateManyToMany($left,$right,Map::getField($leftClass,$field));
			} else if(Map::hasField($rightClass,$field))
			{
				$this->deactivateManyToMany($right,$left,Map::getField($rightClass,$field));
			} else {
				throw new Exception("Field: ".$field.' doesnt exist on '.$leftClass.' or '.$rightClass.'.');
			}
		}
	}
	
	/**
	 * getter TotalRows
	 *
	 * @return int
	 */
	public function getTotalRows()
	{
		return $this->totalRows;
	}
}

?>